import pathlib
import subprocess
import glob
import os
from aec_files import AECFiles
from audio_analysis import AudioAnalysis


class AECTest:
    """
    This class handles the data and methods related to a given test of the mediastreamer2 test suite AEC3, in order to
    run it and analyze its results.
    """

    def __init__(self, test_name, **kwargs):
        """
        Initialization of the class.
        :param test_name: Name of the test function in file mediastreamer2_aec3_tester.c.
        :param kwargs: Dict of optional arguments.
        """

        self.test_name = test_name
        self.suite = "AEC3"
        if "test name in suite" not in kwargs:
            if test_name == "simple_talk_white_noise":
                self.test_suite_name = "Simple talk with white noise"
            elif test_name == "double_talk_white_noise":
                self.test_suite_name = "Double talk with white noise"
            elif test_name == "simple_talk_48000Hz":
                self.test_suite_name = "Simple talk 48000 Hz"
            else:
                self.test_suite_name = test_name.replace("_", " ")
        else:
            self.test_suite_name = kwargs["test name in suite"]

        self.build_path = kwargs.get("build path", "../../Dev/Linphone-sdk/sources/linphone-sdk/out/build/default/")
        self.tester_cmd = kwargs.get("tester cmd", "./" + self.build_path + "/bin/mediastreamer2-tester")
        self.output_path = kwargs.get("output path", self.build_path)
        self.log_file = self.output_path + self.test_name + ".log"

        self.files = AECFiles()
        self.files.aec_output.file_name = self.output_path + self.test_name + ".wav"
        self.start_analysis_time_ms = kwargs.get("start analysis", 0)
        self.results = None

    def run(self):
        """
        Run the related test of mediastreamer2.
        """

        print(f"\n=== run {self.test_name} ===")

        command = [self.tester_cmd, '--suite', self.suite, '--test', self.test_suite_name, '--verbose', '--log-file',
                   self.log_file]
        print(command)
        try:
            result = subprocess.run(command, check=True, capture_output=True, text=True)
            print("Output:", result.stdout)
        except subprocess.CalledProcessError as e:
            print("Error:", e.stderr)

    def move_files(self):
        """Move the files generated by the test to another folder. Make sure that AEC output file is not deleted at the
        end of the test. The output file is the latest wav file starting with aec_output."""

        audio_file_list = glob.glob("aec_output*.wav")
        audio_file_list.sort(key=os.path.getmtime)
        if len(audio_file_list) > 0:
            audio_file_name = audio_file_list[-1]
            print(f"move {audio_file_name}")
            print(f"into {self.files.aec_output.file_name}")
            os.rename(audio_file_name, self.files.aec_output.file_name)
        else:
            print("no audio file in build dir to copy")

    def get_results(self):
        """Extract the AEC metrics from the logs."""

        plot_silence_and_talk = True
        if self.test_name == "far_end_single_talk":
            plot_silence_and_talk = False
        print(f"\nAnalyze results in file\n\t{self.log_file}")
        try:
            self.files.aec_output.read_audio(self.files.sample_rate_hz)
            self.files.nearend.read_audio(self.files.sample_rate_hz)
            self.results = AudioAnalysis(self.files.nearend, self.files.aec_output)
            self.results.compute_echo_cancellation_quality(self.log_file, self.start_analysis_time_ms,
                                                           plot_silence_and_talk)
        except FileNotFoundError:
            print(f"no audio file to analyse")
            self.results = AudioAnalysis(None, None)
            self.results.get_results(self.log_file)

        self.results.print()
        row = {
            "test": self.test_name,
            "input delay": self.results.real_delay_ms,
            "estimated delay": self.results.estimated_delay_ms,
            "final ERL": self.results.aec_metrics.erl_final,
            "final ERLE": self.results.aec_metrics.erle_final,
            "similarity": self.results.similarity_in_speech,
            "max pos": self.results.maxpos,
            "energy in silence": self.results.energy_in_silence,
            "MSTicker late": self.results.msticker_late_ms,
            "test passed": self.results.test_passed,
            "time": self.results.total_time_s,
            "similarity with MFCC": self.results.similarity_mfcc,
            "filter count": self.results.filter_stats[0],
            "filter min time": self.results.filter_stats[1],
            "filter mean time": self.results.filter_stats[2],
            "filter max time": self.results.filter_stats[3],
            "filter std time": self.results.filter_stats[4],
            "filter CPU usage": self.results.filter_stats[5],
            "asserts": self.results.asserts
        }

        return row

    def plot_results(self, fig_file_name=""):
        """Plot the output of AEC filter and related metrics."""

        if self.results.aec_metrics.metrics is not None:
            fig_title = f'Acoustic Echo Cancellation during test {self.test_suite_name}'
            fig = self.results.plot_aec_metrics(fig_title)
            if fig_file_name != "":
                fig.write_image(fig_file_name)
        else:
            print("No AEC metrics to plot.")
